<?php
// +----------------------------------------------------------------------
// | INPHP
// | Copyright (c) 2023 https://inphp.cc All rights reserved.
// | Licensed ( https://opensource.org/licenses/MIT )
// | Author: 幺月儿(https://gitee.com/lulanyin) Email: inphp@qq.com
// +----------------------------------------------------------------------
// | 模块处理
// +----------------------------------------------------------------------
namespace Inphp\Core;

use Inphp\Core\Object\Module;
use Inphp\Core\Object\RouterStatus;
use Inphp\Core\Util\Arr;

class Modules
{
    /**
     * 多模块配置
     * @var array
     */
    private static array $config = [];

    /**
     * 所有模块
     * @var Module[]
     */
    private static array $list = [];

    /**
     * 初始化并加载所有模块
     */
    public static function init(): void
    {
        $config = self::getConfig();
        $list = array_values($config["list"]);
        $list = array_unique($list);
        foreach ($list as $name) {
            //自动加载文件
            if ($module = self::getModule($name)) {
                //保存到列表
                self::$list[$name] = $module;
            }
        }
    }

    /**
     * 获取配置
     * @param string|null $name
     * @return mixed
     */
    public static function getConfig(?string $name = null): mixed
    {
        if (empty(self::$config)) {
            self::$config = Config::get("modules");
        }
        return !is_null($name) ? (Arr::get(self::$config, $name)) : self::$config;
    }

    /**
     * 获取指定模块的配置
     * @param string|null $name
     * @return Module|null
     */
    public static function getModule(?string $name = null): ?Module
    {
        if (is_null($name) && !($name = Context::get("module") ?? null)) {
            return null;
        }
        if (isset(self::$list[$name]) && self::$list[$name] instanceof Module) {
            return self::$list[$name];
        }
        $config = self::getConfig();
        $list = array_values($config["list"]);
        $list = array_unique($list);
        if (in_array($name, $list)) {
            return new Module($config["root"], $config["namespace"], $name);
        }
        return null;
    }

    /**
     * 获取所有模块
     * @return Module[]
     */
    public static function getList(): array
    {
        if (empty(self::$list)) {
            self::init();
        }
        return self::$list;
    }

    /**
     * 刷新所有模块
     */
    public static function refresh(): void
    {
        self::$config = [];
        self::$list = [];
        self::init();
    }

    /**
     * 匹配路由状态
     * @param string $host              客户端请求的域名，例：abc.xxxx.com
     * @param string $uri               请求路径，不带任何参数，并且已删除头尾的斜杠，例：模块入口/子模块名/控制器/方法
     * @param string $requestMethod     请示方式
     * @param string $type              类型
     * @return RouterStatus
     */
    public static function matchRouterStatus(string $host, string $uri = "", string $requestMethod = "GET", string $type = Service::HTTP): RouterStatus
    {
        //先获取配置
        $config = self::getConfig();
        //先从域名中看，是否能得到相应的模块
        $domains = $config["domains"] ?? [];
        if (in_array($host, $domains)) {
            //域名匹配了对应的模块
            $moduleName = array_flip($domains)[$host];
        } else {
            //取得默认模块
            $defaultModuleName = $config["default"];
            //取所有模块列表
            $moduleList = $config["list"];
            //如果未设置或为空，使用第一个
            $defaultModuleName = !empty($defaultModuleName) ? $defaultModuleName : reset($moduleList);
            //如果值不正确，自动修正
            $defaultModuleName = in_array($defaultModuleName, array_values($moduleList)) ? $defaultModuleName : reset($moduleList);
            //处理为模块列表的key值
            $defaultModuleUri = array_flip($moduleList)[$defaultModuleName];
            //如果URI为空，则会进入默认模块的默认index
            $uri = empty($uri) ? $defaultModuleUri : $uri;
            //拆分，取值
            $path = explode("/", $uri);
            //取首个，作为模块入口
            $moduleUri = $path[0];
            //判断是否在配置的模块入口列表里，如果不在，自动修正为默认模块
            if (!in_array($moduleUri, array_keys($moduleList))) {
                //修正为默认模块入口
                $moduleUri = $defaultModuleUri;
                //路径修正
                $path = array_merge([$defaultModuleUri], $path);
            }
            //取处模块名称
            $moduleName = $moduleList[$moduleUri];
            //需要对uri进行处理，去除首个
            $uri = join("/", !empty($path) ? array_slice($path, 1) : $path);
        }
        //取得模块对象
        $module = self::getModule($moduleName);
        return $module->matchRouterStatus($uri, $requestMethod, $type);
    }

    /**
     * 根据路径匹配到目标URL
     * @param string $path
     * @param string|null $moduleName
     * @return string
     */
    public static function matchUri(string $path, ?string $moduleName = null): string
    {
        $query = "";
        if (stripos($path, "?") > 0) {
            list($path, $query) = explode("?", $path, 2);
        }
        $pathArr = explode("/", $path);
        $paths = [];
        foreach ($pathArr as $str) {
            if (!empty($str)) {
                $str = strrchr($str, ".php") === ".php" ? substr($str, 0, -4) : $str;
                $paths[] = $str;
            }
        }
        $list = self::getList();
        $names = array_keys($list);
        if (empty($moduleName)) {
            $moduleName = $paths[0];
            if (in_array($moduleName, $names)) {
                $paths = array_slice($paths, 1);
            } else {
                $moduleName = $names[0];
            }
        }
        if (!isset($list[$moduleName])) {
            return $path;
        }
        $subModuleUri = $list[$moduleName]->matchUri(join("/", $paths));
        //取域名，如果有单独的配置
        $domains = self::getConfig("domains", []);
        $domain = $domains[$moduleName] ?? "";
        if (!empty($domain)) {
            return $domain.str_replace("//", "/", "/{$subModuleUri}").(!empty($query) ? "?{$query}" : "");
        }
        $moduleList = self::getConfig("list");
        $moduleUriList = array_flip($moduleList);
        return str_replace("//", "/", "/{$moduleUriList[$moduleName]}/{$subModuleUri}".(!empty($query) ? "?{$query}" : ""));
    }

    /**
     * 获取控制台菜单
     * @param string|null $name
     * @return array
     */
    public static function getAdminMenus(?string $name): array
    {
        if (!is_null($name)) {
            return self::getModule($name)?->getAdminMenus();
        } else {
            $list = [];
            $modules = self::getList();
            foreach ($modules as $module) {
                $list[] = ["name" => $module->name, "subMenu" => $module->getAdminMenus()];
            }
            return $list;
        }
    }
}